#include "param.h"
#include "spline.h"
#include "evaluar.h"

void cbool(bool a)
{
	if (a) 
		{cout << "True";}
	else
		{cout << "False";}
	
	return;
}

/* Variables Globales. */
long int cant_puntos 	= 1000;
bool logs 				= true;
bool mostrar_splines 	= false;
bool mostrar_puntos 	= true;
bool mostrar_evaluacion	= false;
bool mostrar_graficos 	= true;
bool resultados			= true;

/* ./main entrada.in salida.out nombre_fig */
int main(int argc, char** argv)
{	
	string nombre_entrada, nombre_fig;
	
	if (argc == 2)
	{
		string nombre = argv[1];
		nombre_entrada = nombre + ".in";		
		nombre_fig = nombre;
	}	
	else 
	{
		nombre_entrada = "spline.in";			
		nombre_fig = "spline";		
	}
	
	ifstream entrada(nombre_entrada.c_str());
	cout.precision(12);
	
	int n, m;
	/* n: # puntos de control 
	 * m: # puntos de muestreo. */
	
	entrada >> n >> m;
	
	if (logs)
		cout << "n : " << n << endl;
		
	/* Hacer que la cantidad de puntos en los que se va a 
	 * dividir la curva dependa de n. */
	cant_puntos = cant_puntos * n;
	
	/* Coordenadas (x,y) de los puntos de control. */
	vPunto coordenadas;	
	forn(i, n)
	{
		double X, Y;
		entrada >> X >> Y;
		coordenadas.push_back(Punto(X, Y));		
	}
	
	if (logs)
	{
		cout << endl << "Coordenadas (x,y) de los puntos" << endl;
		
		forn(i, n-1)
			cout << "(" << coordenadas[i].x << ", " << coordenadas[i].y << "), ";
		cout << "(" << coordenadas[n-1].x << ", " << coordenadas[n-1].y << ")" << endl;
	}
	
	double X, Y;
	entrada >> X >> Y;
	Punto click(X, Y);				
	entrada >> X >> Y;
	Punto nuevo(X, Y);
	
	//~ if (logs)
	//~ {
		//~ cout << endl << "Click: (" << click.x << ", " << click.y << ") \t Nueva posición: (" << nuevo.x << ", " << nuevo.y << ")" << endl;
	//~ }
		
	/* Fin lectura de archivo de entrada. */
	
	vdouble param_1 (n);
	vdouble param_2 (n);
	vdouble param_3 (n);
	double  var = 1.0;
	param_Uniforme(param_1, n, var);
	param_Chord(coordenadas, param_2, n, var);
	param_Centripeta(coordenadas, param_3, n, var);
	enRango(param_1, n);
	enRango(param_2, n);
	enRango(param_3, n);
	
	if (logs)
	{
		cout << endl << "Parametrización Uniforme" << endl;	
		forn(i, n)
			cout << param_1[i] << " ";	
		cout << endl;
		
		cout << endl << "Parametrización Chord-length" << endl;	
		forn(i, n)
			cout << param_2[i] << " ";	
		cout << endl;
		
		cout << endl << "Parametrización Centrípeta" << endl;	
		forn(i, n)
			cout << param_3[i] << " ";	
		cout << endl;
	}
	
	/* Armar nuevos puntos de la forma (s_i, x(s_i)) y (s_i, y(x_i)). */
	vPunto puntos_x_1 (n);
	vPunto puntos_y_1 (n);
	vPunto puntos_x_2 (n);
	vPunto puntos_y_2 (n);
	vPunto puntos_x_3 (n);
	vPunto puntos_y_3 (n);
	param_puntos(coordenadas, param_1, puntos_x_1, puntos_y_1, n);
	param_puntos(coordenadas, param_2, puntos_x_2, puntos_y_2, n);
	param_puntos(coordenadas, param_3, puntos_x_3, puntos_y_3, n);
	
	if (mostrar_puntos)
	{
		cout << endl << "Puntos en x. Parametrización Uniforme" << endl;
		forn(i, n-1)
			cout << "(" << puntos_x_1[i].x << ", " << puntos_x_1[i].y << "), ";
		cout << "(" << puntos_x_1[n-1].x << ", " << puntos_x_1[n-1].y << ")" << endl;
		
		cout << endl << "Puntos en y. Parametrización Uniforme" << endl;
		forn(i, n-1)
			cout << "(" << puntos_y_1[i].x << ", " << puntos_y_1[i].y << "), ";
		cout << "(" << puntos_y_1[n-1].x << ", " << puntos_y_1[n-1].y << ")" << endl;
		
		
		cout << endl << "Puntos en x. Parametrización Chord-length" << endl;
		forn(i, n-1)
			cout << "(" << puntos_x_2[i].x << ", " << puntos_x_2[i].y << "), ";
		cout << "(" << puntos_x_2[n-1].x << ", " << puntos_x_2[n-1].y << ")" << endl;
		
		cout << endl << "Puntos en y. Parametrización Chord-length" << endl;
		forn(i, n-1)
			cout << "(" << puntos_y_2[i].x << ", " << puntos_y_2[i].y << "), ";
		cout << "(" << puntos_y_2[n-1].x << ", " << puntos_y_2[n-1].y << ")" << endl;
		
		
		cout << endl << "Puntos en x. Parametrización Centrípeta" << endl;
		forn(i, n-1)
			cout << "(" << puntos_x_3[i].x << ", " << puntos_x_3[i].y << "), ";
		cout << "(" << puntos_x_3[n-1].x << ", " << puntos_x_3[n-1].y << ")" << endl;
		
		cout << endl << "Puntos en y. Parametrización Centrípeta" << endl;
		forn(i, n-1)
			cout << "(" << puntos_y_3[i].x << ", " << puntos_y_3[i].y << "), ";
		cout << "(" << puntos_y_3[n-1].x << ", " << puntos_y_3[n-1].y << ")" << endl;
	}
	
	/* Armar los splines. */
	vSpline spline_x_1 (n-1);
	vSpline spline_y_1 (n-1);
	vSpline spline_x_2 (n-1);
	vSpline spline_y_2 (n-1);
	vSpline spline_x_3 (n-1);
	vSpline spline_y_3 (n-1);
	
	/* Todos los casos de prueba serán con n > 2. */
	interpolar(puntos_x_1, spline_x_1, n);
	interpolar(puntos_y_1, spline_y_1, n);	
	
	interpolar(puntos_x_2, spline_x_2, n);
	interpolar(puntos_y_2, spline_y_2, n);
	
	interpolar(puntos_x_3, spline_x_3, n);
	interpolar(puntos_y_3, spline_y_3, n);
	
	
	if (mostrar_splines)
	{
		cout << endl << "Spline en x. Parametrización Uniforme" << endl;	
		forn(i, n-1)
		{		
			double punto = spline_x_1[i].x_i;
			cout << "S_" << i << "(x) = " << spline_x_1[i].d << "(x-" << punto << ")^3 + ";
			cout << spline_x_1[i].c << "(x-" << punto << ")^2 + ";
			cout << spline_x_1[i].b << "(x-" << punto << ") + ";
			cout << spline_x_1[i].a << "\t";
			cout << " x en [" << spline_x_1[i].min << ", " << spline_x_1[i].max << "]" << endl;
		}
		
		cout << endl << "Spline en y. Parametrización Uniforme" << endl;		
		forn(i, n-1)
		{		
			double punto = spline_y_1[i].x_i;
			cout << "S_" << i << "(y) = " << spline_y_1[i].d << "(y-" << punto << ")^3 + ";
			cout << spline_y_1[i].c << "(y-" << punto << ")^2 + ";
			cout << spline_y_1[i].b << "(y-" << punto << ") + ";
			cout << spline_y_1[i].a << "\t";
			cout << " y en [" << spline_y_1[i].min << ", " << spline_y_1[i].max << "]" << endl;
		}
		
		
		cout << endl << "Spline en x. Parametrización Chord-Length" << endl;	
		forn(i, n-1)
		{		
			double punto = spline_x_2[i].x_i;
			cout << "S_" << i << "(x) = " << spline_x_2[i].d << "(x-" << punto << ")^3 + ";
			cout << spline_x_2[i].c << "(x-" << punto << ")^2 + ";
			cout << spline_x_2[i].b << "(x-" << punto << ") + ";
			cout << spline_x_2[i].a << "\t";
			cout << " x en [" << spline_x_2[i].min << ", " << spline_x_2[i].max << "]" << endl;
		}
		
		cout << endl << "Spline en y. Parametrización Chord-Length" << endl;
		forn(i, n-1)
		{		
			double punto = spline_y_2[i].x_i;
			cout << "S_" << i << "(y) = " << spline_y_2[i].d << "(y-" << punto << ")^3 + ";
			cout << spline_y_2[i].c << "(y-" << punto << ")^2 + ";
			cout << spline_y_2[i].b << "(y-" << punto << ") + ";
			cout << spline_y_2[i].a << "\t";
			cout << " y en [" << spline_y_2[i].min << ", " << spline_y_2[i].max << "]" << endl;
		}
		
		
		cout << endl << "Spline en x. Parametrización Centrípeta" << endl;	
		forn(i, n-1)
		{		
			double punto = spline_x_3[i].x_i;
			cout << "S_" << i << "(x) = " << spline_x_3[i].d << "(x-" << punto << ")^3 + ";
			cout << spline_x_3[i].c << "(x-" << punto << ")^2 + ";
			cout << spline_x_3[i].b << "(x-" << punto << ") + ";
			cout << spline_x_3[i].a << "\t";
			cout << " x en [" << spline_x_3[i].min << ", " << spline_x_1[i].max << "]" << endl;
		}
		
		cout << endl << "Spline en y. Parametrización Centrípeta" << endl;		
		forn(i, n-1)
		{		
			double punto = spline_y_3[i].x_i;
			cout << "S_" << i << "(y) = " << spline_y_3[i].d << "(y-" << punto << ")^3 + ";
			cout << spline_y_3[i].c << "(y-" << punto << ")^2 + ";
			cout << spline_y_3[i].b << "(y-" << punto << ") + ";
			cout << spline_y_3[i].a << "\t";
			cout << " y en [" << spline_y_3[i].min << ", " << spline_y_3[i].max << "]" << endl;
		}
	}
	
	if (logs)
	{
		bool res;
		res = verificar(puntos_x_1, spline_x_1, n);
		if (!res)
			cerr << "Hubo un problema al calcular el spline_1 en x" << endl;	
		res = verificar(puntos_y_1, spline_y_1, n);
		if (!res)
			cerr << "Hubo un problema al calcular el spline_1 en y" << endl;
			
		res = verificar(puntos_x_2, spline_x_2, n);
		if (!res)
			cerr << "Hubo un problema al calcular el spline_2 en x" << endl;	
		res = verificar(puntos_y_2, spline_y_2, n);
		if (!res)
			cerr << "Hubo un problema al calcular el spline_2 en y" << endl;
			
		res = verificar(puntos_x_3, spline_x_3, n);
		if (!res)
			cerr << "Hubo un problema al calcular el spline_3 en x" << endl;	
		res = verificar(puntos_y_3, spline_y_3, n);
		if (!res)
			cerr << "Hubo un problema al calcular el spline_3 en y" << endl;
	}
					
	if (mostrar_graficos)
	{		
		graficar(cant_puntos, nombre_fig + "_uniforme", nombre_fig + " usando parametrizacion uniforme.", spline_x_1, spline_y_1, n);
		graficar(cant_puntos, nombre_fig + "_chord-length", nombre_fig + " usando parametrizacion chord-length.", spline_x_2, spline_y_2, n);
		graficar(cant_puntos, nombre_fig + "_centripeta", nombre_fig + " usando parametrizacion centripeta.", spline_x_3, spline_y_3, n);
	}
			
	/* Para contestar la pregunta 1.
	 * Usar las tres parametrizaciones y evaluar en varios puntos para 
	 * ver si la curva cambia. */	
	vdouble puntos_evaluacion (cant_puntos);
	muestreo_Uniforme(puntos_evaluacion, cant_puntos);
	vPunto muestreo_1 (cant_puntos);
	vPunto muestreo_2 (cant_puntos);
	vPunto muestreo_3 (cant_puntos);	
	evaluar(puntos_evaluacion, muestreo_1, spline_x_1, spline_y_1, n, cant_puntos);
	evaluar(puntos_evaluacion, muestreo_2, spline_x_2, spline_y_2, n, cant_puntos);	
	evaluar(puntos_evaluacion, muestreo_3, spline_x_3, spline_y_2, n, cant_puntos);	
		
	bool es_igual = true;
	double variacion_max;
	double variacion;
	
	/* Todos contra todos. */
	
	/* muestreo_1 vs muestreo_2. */
	variacion_max = 0;
	variacion = 0;
	
	if (resultados)
	{
		forn(i, cant_puntos)
		{
			if (!igualdad_valida(muestreo_1[i].x, muestreo_2[i].x))
			{
				variacion = fabs(muestreo_1[i].x - muestreo_2[i].x);
				
				if (variacion > variacion_max)
					variacion_max = variacion;
					
				es_igual = false;
			}			
			
			if (!igualdad_valida(muestreo_1[i].y, muestreo_2[i].y))
			{
				variacion = fabs(muestreo_1[i].y - muestreo_2[i].y);
				
				if (variacion > variacion_max)
					variacion_max = variacion;
					
				es_igual = false;
			}			
		}
		
		if (!es_igual)
		{
			cout << endl << "La forma de la curva no es la misma usando la parametrización uniforme y la chord-length." << endl;
			cout << "La máxima variación encontrada en los puntos evaluados fue: " << variacion_max << endl;
		}
		else
			cout << endl << "Los valores de la curva son los mismo en los puntos evaluados, usando la parametrización uniforme y la chord-length." << endl;
	}
	
	/* muestreo_1 vs muestreo_3. */
	variacion_max = 0;
	variacion = 0;
	
	if (resultados)
	{
		forn(i, cant_puntos)
		{
			if (!igualdad_valida(muestreo_1[i].x, muestreo_3[i].x))
			{
				variacion = fabs(muestreo_1[i].x - muestreo_3[i].x);
				
				if (variacion > variacion_max)
					variacion_max = variacion;
					
				es_igual = false;
			}			
			
			if (!igualdad_valida(muestreo_1[i].y, muestreo_3[i].y))
			{
				variacion = fabs(muestreo_1[i].y - muestreo_3[i].y);
				
				if (variacion > variacion_max)
					variacion_max = variacion;
					
				es_igual = false;
			}			
		}
		
		if (!es_igual)
		{
			cout << endl << "La forma de la curva no es la misma usando la parametrización uniforme y la centrípeta." << endl;
			cout << "La máxima variación encontrada en los puntos evaluados fue: " << variacion_max << endl;
		}
		else
			cout << endl << "Los valores de la curva son los mismo en los puntos evaluados, usando la parametrización uniforme y la centrípeta." << endl;
	}
	
	/* muestreo_2 vs muestreo_3. */
	variacion_max = 0;
	variacion = 0;
	
	if (resultados)
	{
		forn(i, cant_puntos)
		{
			if (!igualdad_valida(muestreo_3[i].x, muestreo_2[i].x))
			{
				variacion = fabs(muestreo_3[i].x - muestreo_2[i].x);
				
				if (variacion > variacion_max)
					variacion_max = variacion;
					
				es_igual = false;
			}			
			
			if (!igualdad_valida(muestreo_3[i].y, muestreo_2[i].y))
			{
				variacion = fabs(muestreo_3[i].y - muestreo_2[i].y);
				
				if (variacion > variacion_max)
					variacion_max = variacion;
					
				es_igual = false;
			}			
		}
		
		if (!es_igual)
		{
			cout << endl << "La forma de la curva no es la misma usando la parametrización centrípeta y la chord-length." << endl;
			cout << "La máxima variación encontrada en los puntos evaluados fue: " << variacion_max << endl;
		}
		else
			cout << endl << "Los valores de la curva son los mismo en los puntos evaluados, usando la parametrización centrípeta y la chord-length." << endl;
	}	
	
	return 0;
}
